/*
 * scheduler.c
 *
 *  Created on: Feb 16, 2021
 *      Author: taoyu
 */

#include "scheduler.h"
#include "framework_types.h"
#include "framework_events.h"
#include "framework_hooks.h"

typedef struct
{
	struct
	{
		// tick up every Xms, in the interrupt context
		uint8 tick_irq;
		// ready for sleep
		boolean isReadyForSleep;
		// request wake up
		boolean isWakeUpRequested;
		// wake up reason
		uint8 wakeUpReason;
	}
	input;
	struct
	{
		// tick up every Xms, in the main task
		uint8 tick;
		// count ticks and used to schedule the tasks
		uint8 count;
	}
	local;
	struct
	{
		uint8 todo;
	}
	output;
}
SCHEDULER_DATA;

SCHEDULER_DATA sch_Data;

void scheduler_init(void)
{
	sch_Data.input.tick_irq = 0u;
	sch_Data.local.tick = 0u;
	sch_Data.local.count = 0u;
	sch_Data.input.isReadyForSleep = FALSE;
	sch_Data.input.isWakeUpRequested = FALSE;

	// init tasks
	schedulerHook_initTasks();
}

void schedulerEvent_TickUpAwake(void)
{
	sch_Data.input.tick_irq++;
}

static void scheduler_awakeScheduleTasks(void)
{
	uint8 count = sch_Data.local.count;

	schedulerHook_task1();
	if(count & 0x01u) schedulerHook_task2();
	else if(count & 0x02u) schedulerHook_task4();
	else if(count & 0x04u) schedulerHook_task8();
	else if(count & 0x08u) schedulerHook_task16();
	else if(count & 0x10u) schedulerHook_task32();
	else if(count & 0x20u) schedulerHook_task64();
	else if(count & 0x40u) schedulerHook_task128();
	else if(count & 0x80u) schedulerHook_task256();
	else;
}

void scheduler_awake(void)
{
	// sync ticks
	sch_Data.local.tick = sch_Data.input.tick_irq;

	// clear the sleep ready
	sch_Data.input.isReadyForSleep = FALSE;

	// all task enter awake
	schedulerHook_enterAwake();

	// dead loop
	do
	{
		uint8 tick;

		// this should be protected as shared variable between interrupt and main
		tick = sch_Data.input.tick_irq;

		// tick up => schedule the tasks
		if( sch_Data.local.tick != tick )
		{
			// sync main with interrupt
			sch_Data.local.tick = tick;

			// count ticks
			sch_Data.local.count++;

			// schedule the tasks
			scheduler_awakeScheduleTasks();

			// update ready for sleep
			sch_Data.input.isReadyForSleep = schedulerHook_isReadyForSleep();
		}
		// no tick => idle
		else
		{
			schedulerHook_idle();
		}
	}
	while(sch_Data.input.isReadyForSleep==FALSE);

	// all task exit awake
	schedulerHook_exitAwake();
}

void scheduler_asleep(void)
{
	// clear the request
	sch_Data.input.isWakeUpRequested = FALSE;

	// all task enter asleep
	schedulerHook_enterAsleep();

	// while loop
	do
	{
		// stop mcu
		powermodeHook_stop();

		// after interrupt, run the task
		schedulerHook_taskAsleep();
	}
	while(sch_Data.input.isWakeUpRequested==FALSE);

	// all task exit asleep
	schedulerHook_exitAsleep();
}

void scheduler_requestWakeUp(uint8 reason)
{
	sch_Data.input.isWakeUpRequested = TRUE;
	sch_Data.input.wakeUpReason = reason;
}

void schedulerEvent_TickUpAsleep(void)
{

}
